package com.smartx.app.fragment;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.DividerItemDecoration;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.smartx.app.R;
import com.smartx.app.SatApp;
import com.smartx.app.adapter.TransactionListAdapter;
import com.smartx.app.dialog.InputPwdDialogFragment;
import com.smartx.app.dialog.LoadingDialog;
import com.smartx.app.dialog.MnemonicDialog;
import com.smartx.app.dialog.SetPwdDialogFragment;
import com.smartx.app.model.TransactionModel;
import com.smartx.app.util.DefaultHttpRequest;
import com.smartx.app.util.HttpRequestManager;
import com.smartx.config.Constants;
import com.smartx.core.Wallet;
import com.smartx.crypto.Hex;
import com.smartx.crypto.Key;
import com.smartx.crypto.bip39.MnemonicGenerator;

import org.json.JSONObject;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING;
import static android.support.v7.widget.RecyclerView.SCROLL_STATE_SETTLING;

public class TransactionFragment extends Fragment implements View.OnClickListener,SwipeRefreshLayout.OnRefreshListener{

    private static final String TAG="Transaction";
    private int lastViewItemIdx;
    private int totalCount;
    private boolean isScolled = false;//是否可以滑动
    private TransactionListAdapter txListAdapter;
    private List<TransactionModel> txList;
    private TextView mTvBalance;
    private RecyclerView mRecyclerView;
    private SwipeRefreshLayout mSwipeRefreshLayout;
    private LinearLayoutManager mLayoutManager;
    private InputPwdDialogFragment mInputPwdDialogFragment;
    private SetPwdDialogFragment mSetPwdDialogFragment;
    private MnemonicDialog mMnemonicDialog;
    private LoadingDialog loadingDialog;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_transactions,container,false);
        initView(view);
        initData();
        return view;
    }

    private void initData() {
        if(SatApp.getInstance().getWallet()!=null){
            loadBalance();
            loadTransactionList();
        }else{
            loadWallet();
        }
    }

    private void initView(View view){
        txList = new ArrayList<>();
        txListAdapter = new TransactionListAdapter(getContext(),txList);
        mTvBalance = view.findViewById(R.id.tv_balance);
        mSwipeRefreshLayout = view.findViewById(R.id.refresh_layout);
        mRecyclerView = view.findViewById(R.id.transaction_list);
        mLayoutManager = new LinearLayoutManager(getContext());
        mLayoutManager.setOrientation(OrientationHelper.VERTICAL);
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        mRecyclerView.setAdapter(txListAdapter);
        DividerItemDecoration divider = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
        divider.setDrawable(ContextCompat.getDrawable(getContext(), R.drawable.transaction_recycler_view_divider));
        mRecyclerView.addItemDecoration(divider);

        //RecyclerView 只能上拉刷新，下拉刷新需要靠SwipeRefreshLayout监听
        // 下拉刷新的圆圈是否显示
        mSwipeRefreshLayout.setRefreshing(true);

        //设置下拉时圆圈的颜色（可以由多种颜色拼成）
        mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_light,
                android.R.color.holo_red_light,
                android.R.color.holo_orange_light);

        //设置下拉时圆圈的背景颜色（这里设置成白色）
        mSwipeRefreshLayout.setProgressBackgroundColorSchemeResource(android.R.color.white);

        //设置下拉刷新时的操作
        mSwipeRefreshLayout.setOnRefreshListener(this);

        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                if (newState == SCROLL_STATE_DRAGGING || newState == SCROLL_STATE_SETTLING) {
                    isScolled = true;
                } else {
                    isScolled = false;
                }
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
                    RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
                    totalCount = txList.size();
                    lastViewItemIdx = ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();
                }

                if (isScolled && totalCount != lastViewItemIdx && lastViewItemIdx == totalCount - 1) {
                    loadTransactionList();
                }
            }
        });
    }

    private void loadBalance(){
        DefaultHttpRequest request = new DefaultHttpRequest() {
            @Override
            public void onSuccess(String json) {
                Log.d(TAG,"get balance success " + json);
                try {
                    List<TransactionModel> itemList = TransactionModel.getTransactionList(json);
                    JSONObject jsonObject = new JSONObject(json);
                    JSONObject resultObject = jsonObject.getJSONObject("result");
                    String balance = resultObject.getString("available");
                    mTvBalance.setText(balance + " SAT");
                }catch (Exception e){
                    e.printStackTrace();
                }
            }

            @Override
            public String url() {
                return Constants.URL_GET_ACCOUNT_BALANCE;
            }
        };

        request.params().put("address",SatApp.getInstance().getCoinBaseAddress());
        HttpRequestManager.manager().get(request);
    }

    private void loadTransactionList(){
        Log.i(TAG,"loading transaction list");
        DefaultHttpRequest request = new DefaultHttpRequest() {
            @Override
            public void onSuccess(String json) {
                Log.d(TAG,"get tx list success " + json);
                try {
                    List<TransactionModel> itemList = TransactionModel.getTransactionList(json);

                    //后端rpc已经做了排序，如果最新的hash值跟当前列表的最新hash值一样，则不更新
                    //TODO:后端做分页查询，前端根据页码来判断是否刷新
                    if(txList != null && txList.size() > 0){
                        String hashRemote = itemList.get(0).hash;
                        String hashLocal = txList.get(0).hash;
                        if(hashRemote.equals(hashLocal)){
                            Log.i(TAG,"remote latest hash equals local do not refresh");
                            //关闭刷新
                            mSwipeRefreshLayout.setRefreshing(false);
                            return;
                        }
                    }

                    //TODO:分页查询做了的话，就不需要clear，可以addAll新刷下来的数据
                    txList.clear();
                    txList.addAll(itemList);
                    txListAdapter.notifyDataSetChanged();

                    //关闭刷新
                    mSwipeRefreshLayout.setRefreshing(false);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }

            @Override
            public String url() {
                return Constants.URL_GET_TX_LIST;
            }
        };

        request.params().put("address",SatApp.getInstance().getCoinBaseAddress());
        HttpRequestManager.manager().get(request);
    }

    private void loadWallet() {
        //钱包文件不存在则跳转到创建钱包页面
        //TODO:弹出设置密码对话框
        File file = new File(Constants.WalletDataFilePath);
        if(!file.exists()){
            showSetPwdDialog(getResources().getString(R.string.please_set_password));
            return;
        }
        showInputPwdDialog(getResources().getString(R.string.please_input_password));
    }

    private void showLoadingDialog(String title,boolean isCancelAble){
        if (getContext() == null) {
            return;
        }
        if (loadingDialog == null) {
            loadingDialog = new LoadingDialog(getContext());
            loadingDialog.setTitle(title);
            loadingDialog.setCancelable(isCancelAble);
        }
        if (loadingDialog != null && !loadingDialog.isShowing())
            loadingDialog.show();
    }

    public void dismissLoadingDialog() {
        try {
            if (loadingDialog != null && loadingDialog.isShowing()) {
                loadingDialog.dismiss();
            }
        } catch (Exception e) {
        }
    }

    private void showSetPwdDialog(String title){
        //set password to create wallet
        if(mSetPwdDialogFragment == null){
            mSetPwdDialogFragment = new SetPwdDialogFragment();
        }

        Bundle bundle = new Bundle();
        bundle.putString("title",title);
        mSetPwdDialogFragment.setArguments(bundle);
        mSetPwdDialogFragment.setTargetFragment(TransactionFragment.this,Constants.REQUEST_CODE_SET_PWD);
        mSetPwdDialogFragment.show(getFragmentManager(),"set password");
    }

    private void showInputPwdDialog(String title){
        //input password to unlock wallet
        if(mInputPwdDialogFragment == null){
            mInputPwdDialogFragment = new InputPwdDialogFragment();
        }

        Bundle bundle = new Bundle();
        bundle.putString("title",title);
        mInputPwdDialogFragment.setArguments(bundle);
        mInputPwdDialogFragment.setTargetFragment(TransactionFragment.this,Constants.REQUEST_CODE_INPUT_PWD_LOGIN);
        mInputPwdDialogFragment.show(getFragmentManager(),"input password");
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode== Constants.REQUEST_CODE_INPUT_PWD_LOGIN){
            if(resultCode == Activity.RESULT_OK){
                String password= data.getStringExtra(InputPwdDialogFragment.PASSWORD);
                Log.i(TAG,"input password is " + password);
                mInputPwdDialogFragment.dismiss();
                loadWalletFileWithPwd(password);
            }else {
                Log.i(TAG,"input password canceled");
                mInputPwdDialogFragment.dismiss();
                return;
            }
        }else if(requestCode == Constants.REQUEST_CODE_SET_PWD){
            if(resultCode == Activity.RESULT_OK){
                String password1 = data.getStringExtra(SetPwdDialogFragment.PASSWORD1);
                String password2 = data.getStringExtra(SetPwdDialogFragment.PASSWORD2);
                if(password1.equals(password2)){
                    mSetPwdDialogFragment.dismiss();
                    //TODO:弹出加载框
                    createNewWallet(password1);

                }else{
                    //TODO:提示UI两次密码不一致
                    mSetPwdDialogFragment.dismiss();
                    Log.e(TAG,"password not the same");
                    showSetPwdDialog(getResources().getString(R.string.error_passwords_must_match));
                    return;
                }

            }else{
                Log.w(TAG,"illegal result code from set password dialog" + resultCode);
                return;
            }

        }else if(requestCode == Constants.REQUEST_CODE_COPY_MNEMONIC){
            if(resultCode == Activity.RESULT_OK){
                String mnemonic = data.getStringExtra(MnemonicDialog.MNEMONIC);
                Log.i(TAG,"copy mnemonic : " + mnemonic);
                mMnemonicDialog.dismiss();
                return;
            }else{
                mMnemonicDialog.dismiss();
                Log.w(TAG,"illegal result code from copy mnemonic dialog" + resultCode);
                return;
            }
        }else{
            Log.w(TAG,"unknow request code from dialog" + requestCode);
            return;
        }
        return;
    }

    private Wallet createNewWallet(String password) {

        try{
            //TODO: 根据是debug还是prd来决定创建MAINNET还是TESTNET
            File walletDataFile = new File(Constants.WalletDataFilePath);
            Wallet wallet = new Wallet(walletDataFile, SatApp.getInstance().getNetwork());

            if(!wallet.exists()){
                //TODO:提示UI，读取钱包文件失败
                if(walletDataFile.exists()){
                    Log.i(TAG,"wallet file exist but wallet not exist remove the illeagal file");
                    walletDataFile.delete();
                }

                //创建新的钱包文件
                if(!walletDataFile.createNewFile()){
                    //TODO:提示UI，创建钱包文件失败
                    Log.e(TAG,"create new wallet.data failed");
                    return null;
                }

                //解压生成钱包所必须的基础信息
                if (!wallet.unlock(password)) {
                    //TODO:提示UI，解锁钱包失败
                    Log.e(TAG,"create wallet failed unlock wallet failed");
                    return null;
                }

                //刷新基础信息到钱包文件
                if(!wallet.flush()){
                    //TODO:提示UI，刷新信息到钱包失败
                    Log.e(TAG,"create wallet failed save wallet failed");
                    return null;
                }

                if(!wallet.isUnlocked()){
                    //TODO:提示UI，解锁钱包失败
                    Log.e(TAG,"wallet is unlocked can not add hd account");
                    return null;
                }

                //[1]生成助记词，首先生成随机熵，再根据随机熵从字典当中随机选出助记词
                InputStream stream = getResources().openRawResource(R.raw.english);
                MnemonicGenerator generator = new MnemonicGenerator();
                String phrase = generator.getWordlist(Wallet.MNEMONIC_ENTROPY_LENGTH, Wallet.MNEMONIC_LANGUAGE,stream);
                Log.i(TAG,"generate mnemonic words : " + phrase);
                wallet.initializeHdWallet(phrase);
                stream.close();

                //[2]根据随机出来的助记词 --> 生成盐 --> 根据盐生成随机种子-->根据随机种子生成私钥-->根据私钥生成公钥
                stream = getResources().openRawResource(R.raw.english);
                wallet.addAccountWithNextHdKey(generator,stream);
                stream.close();

                //[3]更新账户信息到钱包
                wallet.flush();

                List<Key> accountList = wallet.getAccounts();
                if(accountList != null && accountList.size() > 0){
                    Key key = accountList.get(0);
                    Log.i(TAG,"create new wallet address " + key.toAddressString());
                    Log.i(TAG,"create new wallet private key " + Hex.encode(key.getPrivateKey()));
                    Log.i(TAG,"create new wallet public key " + Hex.encode(key.getPublicKey()));
                    Log.i(TAG,"create new wallet account size " + accountList.size());

                    SatApp.getInstance().setWallet(wallet);

                    //set current account
                    SatApp.getInstance().setCoinBase(0);

                    //lock the wallet ,unlock when needed
                    wallet.lock();

                    //TODO:创建钱包成功后还需要显示助记词，然后让用户确认记住了助记词
                    Bundle mnemonicBundle = new Bundle();
                    mnemonicBundle.putString(MnemonicDialog.MNEMONIC,phrase);
                    mMnemonicDialog = new MnemonicDialog();
                    mMnemonicDialog.setTargetFragment(TransactionFragment.this,Constants.REQUEST_CODE_COPY_MNEMONIC);
                    mMnemonicDialog.setArguments(mnemonicBundle);
                    mMnemonicDialog.show(getFragmentManager(),"show mnemonic");
                }
            }

        }catch (Exception e){
            //TODO:提示UI创建钱包异常
            Log.e(TAG,"generate wallet exception ");
            e.printStackTrace();
            return null;
        }
        return null;
    }

    //钱包文件存在才调用该函数
    private void loadWalletFileWithPwd(String password){

        Log.i(TAG,"input pass word " + password);

        //TODO: 根据是debug还是prd来决定创建MAINNET还是TESTNET
        File file = new File(Constants.WalletDataFilePath);
        Wallet wallet = new Wallet(file, SatApp.getInstance().getNetwork());
        if(wallet.unlock(password) && wallet.flush()){
            Log.i(TAG,"unlock wallet success");
            List<Key> accountList = wallet.getAccounts();
            if(accountList == null || accountList.size() <=0){
                Log.e(TAG,"no account found in wallet");
                return;
            }
            Key key = accountList.get(0);
            Log.i(TAG,"create new walle" + key.toAddressString());
            Log.i(TAG,"create new wallet private key " + Hex.encode(key.getPrivateKey()));
            Log.i(TAG,"create new wallet public key " + Hex.encode(key.getPublicKey()));
            Log.i(TAG,"create new wallet account size " + accountList.size());

            //设置钱包和默认账户
            SatApp.getInstance().setWallet(wallet);
            SatApp.getInstance().setCoinBase(0);

            //加载金额和交易流水
            loadBalance();
            loadTransactionList();
        }else{
            //TODO:提示UI密码错误，要求重新输入密码
            Log.i(TAG,"unlock wallet failed");
            showInputPwdDialog(getResources().getString(R.string.error_incorrect_password));
        }

        //重新锁定钱包
        wallet.lock();
    }

    @Override
    public void onResume(){
        super.onResume();
    }

    @Override
    public void onClick(View view) {

    }

    @Override
    public void onRefresh() {
        loadTransactionList();
    }
}
